import json
import re

from django.contrib.auth import logout

from apps.ausers.models import User, Address

from django import http
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render, redirect
from django.urls import reverse
from django.views import View
from django_redis import get_redis_connection

from apps.ausers.models import User
from apps.ausers.utils import generate_verify_email_url
from apps.carts.utils import merge_cart_cookie_to_redis
from apps.goods.models import SKU
from utils.response_code import RETCODE
from utils.secret import SecretOauth
# 15.浏览记录
# 14. 显示 密码 修改
class ChangePwdView(LoginRequiredMixin, View):
    def get(self, request):
        return render(request, 'user_center_pass.html')

    def post(self, request):

        # 1.接收参数
        old_password = request.POST.get('old_pwd')
        new_password = request.POST.get('new_pwd')
        new_password2 = request.POST.get('new_cpwd')

        # 2. 校验 判空 判正则  是否一致

        # 3. 原始密码是否正确
        try:
            request.user.check_password(old_password)
        except Exception as e:
            logger.error(e)
            return render(request, 'user_center_pass.html', {'origin_pwd_errmsg':'原始密码错误'})

        # 4. 重置密码
        request.user.set_password(new_password)
        request.user.save()

        # 5. 清空状态, 删除cookie, 登录页
        logout(request)
        response = redirect(reverse('users:login'))
        response.delete_cookie('username')

        return response

class HistoryBrowseView(LoginRequiredMixin, View):
    def get(self, request):
        # *   1. 取出redis的 sku_ids
        redis_client = get_redis_connection('history')
        sku_ids = redis_client.lrange('history_' + str(request.user.id), 0, -1)

        # *   2.遍历sku_ids 取出数据库对应商品SKU
        skus = []
        for sku_id in sku_ids:
            sku = SKU.objects.get(id=sku_id)
            skus.append({
                'id': sku.id,
                'name': sku.name,
                "default_image_url": sku.default_image.url,
                "price": sku.price
            })
        # *   3. 返回前端
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'skus': skus})

    def post(self, request):
        # 1.解析 sku_id
        sku_id = json.loads(request.body.decode()).get('sku_id')

        # 2.校验
        try:
            sku = SKU.objects.get(id=sku_id)
        except Exception as e:
            return http.HttpResponseForbidden('商品不存在!')

        # 3. 存redis
        redis_client = get_redis_connection('history')
        redis_key = 'history_' + str(request.user.id)

        p1 = redis_client.pipeline()

        # 3.1 先去重
        p1.lrem(redis_key, 0, sku_id)
        # 3.2 再存储
        p1.lpush(redis_key, sku_id)
        # 3.3 截取
        p1.ltrim(redis_key, 0, 4)

        p1.execute()

        # 4 返回
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})
# 13.设置标题
class TitleAddressView(LoginRequiredMixin, View):
    def put(self, request, address_id):

        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')

        try:
            # 1.取出当前的地址
            address = Address.objects.get(id=address_id)
            # 2.修改title值
            address.title = title
            # 3.保存
            address.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '设置地址标题失败'})

            # 4.响应删除地址结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '设置地址标题成功'})


# 12.设置默认地址
class DefaultAddressView(LoginRequiredMixin, View):
    def put(self, request, address_id):

        try:
            address = Address.objects.get(id=address_id)
            request.user.default_address = address
            request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '设置默认地址失败'})

                # 响应设置默认地址结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '设置默认地址成功'})


# 11. 修改和删除
class UpdateDestroyAddressView(LoginRequiredMixin, View):
    # 修改
    def put(self, request, address_id):
        # 1.接收参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 2.校验 正则校验

        # 3. Address.objects.filter().update()
        try:
            Address.objects.filter(id=address_id).update(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '更新地址失败'})

        # 4. 返回前端的格式 --dict
        address = Address.objects.get(id=address_id)
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        # 响应更新地址结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '更新地址成功', 'address': address_dict})
    # 删除
    def delete(self, request, address_id):
        try:
            address = Address.objects.get(id=address_id)
            address.is_deleted = True
            address.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '删除地址失败'})

        # 响应删除地址结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '删除地址成功'})


# 10.新增地址
class CreateAddressView(LoginRequiredMixin, View):
    def post(self, request):

        # 判断 地址的个数,如果大于20 不允许增加
        count = Address.objects.filter(user=request.user, is_deleted=True).count()
        count = request.user.addresses.filter(is_deleted=True).count()

        if count > 20:
            return http.JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '超过地址数量上限'})

        # 1.接收参数 body
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 2.校验 判空判断正则

        # 3.交互数据库 Address.objects.create()
        try:
            address = Address.objects.create(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )

            # 判断 用户是否有 默认地址, 如果没有 设置一个
            if not request.user.default_address:
                request.user.default_address = address
                request.user.save()


        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '新增地址失败'})

        # 4.构建前端的数据格式 字典{}
        address_dict = {
            "id": address.id,
            "title": address.receiver,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '新增地址成功', 'address': address_dict})


# 9.显示收货地址
class AddressView(LoginRequiredMixin, View):
    def get(self, request):
        # 1.获取所有的地址 没有删除的地址
        user = request.user
        addresses = Address.objects.filter(user=user, is_deleted=False)

        # 2. 构建前端的数据
        address_dict_list = []
        for address in addresses:
            address_dict_list.append({
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            })

        context = {
            'default_address_id': user.default_address_id,
            'addresses': address_dict_list,
        }

        return render(request, 'user_center_site.html', context)


# 8.激活邮箱　
class VerifyEmailView(LoginRequiredMixin,View):
    def get(self,request):
        # 1.解析参数　密文
        token = request.GET.get('token')
        # 2.解密
        token_dict = SecretOauth().loads(token)
        # 3.数据库校验Ｕｓｅｒ
        try:
            user = User.objects.get(id = token_dict['user_id'],email=token_dict['email'])
        except Exception as e:
            logger.error(e)
            return http.HttpResponseForbidden('无效的token')
        # 4.改email_active字段
        try:
            user.email_active = True
            user.save()
        except Exception as e:
            logger.error(e)
            return http.HttpResponseServerError('激活邮件失败')

        # 5.返回响应 个人中心
        return redirect(reverse('ausers:info'))
# 7.修改邮箱的值
class EmailView(LoginRequiredMixin, View):
    def put(self, request):

        # 1.接收　解析参数　ｂｏｄｙ
        email = json.loads(request.body.decode()).get('email')
        # 2.正则校验
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return http.HttpResponseForbidden('参数email有误')

        # 3.修改数据库的 email字段
        try:
            request.user.email = email
            request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '添加邮箱失败'})


        # 发邮件
        from celery_tasks.email.tasks import send_verify_email
        verify_url = generate_verify_email_url(request.user)
        send_verify_email.delay(email, verify_url)
        # 4.返回响应数据
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '添加邮箱成功'})
# 6.用户中心
class UserInfoView(LoginRequiredMixin, View):
    def get(self, request):
        """提供个人信息界面"""
        context = {
            'username': request.user.username,
            'mobile': request.user.mobile,
            'email': request.user.email,
            'email_active': request.user.email_active
        }
        return render(request, 'user_center_info.html', context)
# 5.退出
class LogoutView(View):
    def get(self, request):
        from django.contrib.auth import logout

        # 退出 登录 logout
        logout(request)

        # 调到 login.html
        response = redirect(reverse('users:login'))
        # 删除cookie
        response.delete_cookie('username')

        return response
# 4.登录页显示功能
class LoginView(View):
    def get(self,request):
        return render(request, 'login.html')

    def post(self, request):
        # *   2.接收参数
        username = request.POST.get('username')
        password = request.POST.get('password')
        remembered = request.POST.get('remembered')

        # *   3. 解析校验 判空 和判断正则
        # *   4. 数据交互 username,password  django自带的认证函数
        from django.contrib.auth import authenticate, login
        user = authenticate(username=username, password=password)

        # 登录失败
        if user is None:
            return render(request, 'login.html', {'account_errmsg': '用户名或密码错误'})

        # *   5. 保持登录状态
        login(request, user)

        # *   6. 记住登录
        if remembered != "on":
            # 不记住 --会话结束 就失效了
            request.session.set_expiry(0)
        else:
            # 记住----2周
            request.session.set_expiry(None)

        # 6.用户中心　　ｎｅｘｔ记录上一个页面的路由
        next = request.GET.get('next')
        if next:
            response = redirect(next)
        else:
            # *   7. 跳转首页 index
            response = redirect(reverse('contents:index'))
        # 合并购物车
        merge_cart_cookie_to_redis(request, user, response)

        response.set_cookie('username', username, max_age=14 * 3600 * 24)
        return response
# 3.判断手机号是否重复
class MobileCountView(View):
    def get(self, request, mobile):
        #1.接受参数　mobile
        #2.校验参数　　判空　判正则

        #3.数据库查询个数
        try:
            count = User.objects.filter(mobile=mobile).count()
        except Exception as e:
            logger.error(e)
            return http.HttpResponseForbidden('手机号不存在')
        # 4.返回前端个数
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'count': count})
# 2.判断用户名重复
class UsernameCountView(View):
    def get(self, request, username):
        # *    1.接收用户名 username
        # *    2.校验判空 和 正则
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden('请输入5-20个字符的用户名')
        # *    3.逻辑数据库查询 User.objects.get(username=username).count()
        try:
            from apps.ausers.models import User
            count = User.objects.filter(username=username).count()
        except Exception as e:
            logger.error(e)
            return http.HttpResponseForbidden('不存在!')

        # *    4.返回给前端 json
        from utils.response_code import RETCODE
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': "查询成功", "count": count})
# 1.注册用户
from meiduo_mall.settings.dev import logger
class RegisterView(View):
    """用户注册"""

    def get(self, request):
        """
        提供注册界面
        :param request: 请求对象
        :return: 注册界面
        """
        return render(request, 'register.html')

# 2.注册功能　　

    def post(self, request):
        """
        实现用户注册
        :param request: 请求对象
        :return: 注册结果
        """
        # 多选--alt(option) + 单击
        # 1.接收参数 request.POST
        username = request.POST.get('username')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        mobile = request.POST.get('mobile')
        allow = request.POST.get('allow')
        sms_code = request.POST.get('msg_code')
        # sms_code

        # 2.校验参数
        # 2.1 判空  all判断多个为空　　
        if not all([username, password, password2, mobile]):
            return http.HttpResponseForbidden('参数不能为空!')

        # 1.用户名: ---------判空,正则校验,是否重复
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden('请输入5-20个字符的用户名')
        # 2.密码:   --------- 判空,正则校验
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseForbidden('请输入8-20个密码')
        # 3.确认密码: ---------判空,判断是否相等
        if password != password2:
            return http.HttpResponseForbidden('两次密码不一致')

        # 4.手机号:---------   判空,正则校验,是否重复
        if not re.match(r'^1[345789]\d{9}$', mobile):
            return http.HttpResponseForbidden('手机号格式有误!')



        # 7.同意”美多商城用户使用协议“: 判断是否选中
        if allow != 'on':
            # 没有勾选
            return http.HttpResponseForbidden('请勾选协议')
        # 6.短信验证码:
        # 6.1.导包
        # from django_redis import get_redis_connection
        # 6.2.链接
        sms_redis_client = get_redis_connection('sms_code')

        # 6.3 取值
        sms_redis_code = sms_redis_client.get("sms_%s" % mobile)

        # 6.4 判断
        if sms_redis_code is None:
            return render(request, 'register.html', {'sms_code_errmsg': '无效的短信验证码'})

        # 千万注意: redis取出来的bytes.decode()
        if sms_code != sms_redis_code.decode():
            return render(request, 'register.html', {'sms_code_errmsg': '短信验证码验证失败!'})

        # 3.注册用户 djdango自带的User的函数 create_user()
        try:
            from apps.ausers.models import User
            user = User.objects.create_user(username=username, password=password, mobile=mobile)
        except Exception as e:
            logger.info(e)
            return render(request, 'register.html', {'register_message': "注册失败"})

        # 保持登录状态
        from django.contrib.auth import login
        login(request, user)

        # 4.返回响应
        # return redirect('/')
        response = redirect(reverse('contents:index'))
        response.set_cookie('username', username, max_age=14 * 3600 * 24)
        return response

